package com.yg.service.impl;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import com.alibaba.excel.exception.ExcelDataConvertException;
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yg.config.FilePathConfig;
import com.yg.config.result.R;
import com.yg.config.result.ResultCode;
import com.yg.entity.readAndWriteTemplates.TechnologyCompetitionTemplate;
import com.yg.entity.singleEntity.TechnologyCompetition;
import com.yg.entity.singleEntity.TechnologyCompetitionAward;
import com.yg.mapper.TechnologyCompetitionAwardMapper;
import com.yg.mapper.TechnologyCompetitionMapper;
import com.yg.service.TechnologyCompetitionService;
import com.yg.utils.DateValidationUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

/**
 * <p>
 * 对应sheet13，此表是教师指导大学生参加科技竞赛表 服务实现类
 * </p>
 *
 * @author YingGu
 * @since 2020-11-04
 */
@Service
@Slf4j
public class TechnologyCompetitionServiceImpl extends ServiceImpl<TechnologyCompetitionMapper, TechnologyCompetition> implements TechnologyCompetitionService {

    @Autowired
    FilePathConfig filePathConfig;

    @Resource
    TechnologyCompetitionMapper technologyCompetitionMapper;
    @Resource
    TechnologyCompetitionAwardMapper technologyCompetitionAwardMapper;


    /**
     * 模板文件地址
     */
    /**
     * 导出文件名
     */
    String outputFileName = "sheet13_output.xlsx";


    /**
     * excel写入
     *
     * @return 统一返回R类
     */
    @Transactional
    @Override
    public R readExcel(MultipartFile file) {
        log.info("执行了" + this.getClass().getName() + "的readExcel方法");
        //创建要录入的bean的list
        List<TechnologyCompetition> technologyCompetitionList = new ArrayList<>();
        List<TechnologyCompetitionAward> technologyCompetitionAwardList = new ArrayList<>();
        //创建R
        R r = R.getR();
        r.setCode(ResultCode.SUCCESS);
        //存储错误信息
        List<String> errorList = new ArrayList<>();

        //读取excel(匿名内部类解决传参问题)
        try {
            EasyExcel.read(file.getInputStream(), TechnologyCompetitionTemplate.class, new AnalysisEventListener<TechnologyCompetitionTemplate>() {
                /**
                 * 处理单元格
                 * @param template
                 * @param analysisContext
                 */
                @Override
                public void invoke(TechnologyCompetitionTemplate template, AnalysisContext analysisContext) {

                    //每行执行
                    //创建数据库对应实体类
                    TechnologyCompetition technologyCompetition = new TechnologyCompetition();
                    TechnologyCompetitionAward technologyCompetitionAward = new TechnologyCompetitionAward();
                    //捕获日期校验工具抛出的异常并返回相关信息
                    try {
                        template.setTime(DateValidationUtil.dateValidation(template.getTime(), "yyyy.MM"));
                        template.setAwardTime(DateValidationUtil.dateValidation(template.getAwardTime(), "yyyy.MM"));
                    } catch (Exception e) {
                        r.success(false).code(ResultCode.UTILERROR).message("日志格式转换异常，请检查是否为'yyyy.MM'或'yyyy.MM.dd'格式！");
                        return;
                    }

                    BeanUtils.copyProperties(template, technologyCompetition);
                    BeanUtils.copyProperties(template, technologyCompetitionAward);
                    String category = template.getCategory();
                    if ("国家级".equals(category)) {
                        technologyCompetition.setCategory("1");
                    } else if ("省部级".equals(category)) {
                        technologyCompetition.setCategory("2");
                    } else if ("校级".equals(category)) {
                        technologyCompetition.setCategory("3");
                    }

                    log.info("entity:--------------" + technologyCompetition);
                    log.info("entity:--------------" + technologyCompetitionAward);
                    technologyCompetitionList.add(technologyCompetition);
                    technologyCompetitionAwardList.add(technologyCompetitionAward);

                }

                //所有行读完执行
                @Override
                public void doAfterAllAnalysed(AnalysisContext analysisContext) {

                    if (r.getCode() == ResultCode.SUCCESS) {
                        //向数据库插入数据
                        saveData();
                    } else {
                        //添加错误信息
                        r.data("errorMsg", errorList);
                    }
                }

                /**
                 * 数据类型转换异常处理
                 * @param exception
                 * @param context
                 * @throws Exception
                 */

                @Override
                public void onException(Exception exception, AnalysisContext context) {
                    if (exception instanceof ExcelDataConvertException) {
                        ExcelDataConvertException excelDataConvertException = (ExcelDataConvertException) exception;

                        //向errorList中添加信息
                        r.code(ResultCode.ERROR);
                        System.out.println("行:" + excelDataConvertException.getRowIndex() + "列:" + excelDataConvertException.getColumnIndex());
                        errorList.add("行：" + excelDataConvertException.getRowIndex() + "列" + excelDataConvertException.getColumnIndex());

                    }
                }

                //存数据库操作
                private void saveData() {
                    for (int i = 0; i < technologyCompetitionList.size(); i++) {
                        System.out.println(technologyCompetitionList.get(i));
                        technologyCompetitionMapper.insert(technologyCompetitionList.get(i));
                        String id = technologyCompetitionList.get(i).getId();
                        technologyCompetitionAwardList.get(i).setId(id);
                        technologyCompetitionAwardMapper.insert(technologyCompetitionAwardList.get(i));

                        System.out.println("插入成功");
                    }
                    r.success(true).code(ResultCode.SUCCESS).message("插入成功" + technologyCompetitionAwardList.size() + "条数据");
                }
            }).headRowNumber(5).sheet().doRead();
        } catch (IOException e) {
            e.printStackTrace();
            r.success(false).code(ResultCode.WRITEERROR).message("文件导入失败");
        }


        return r;
    }


    /**
     * excel写出
     *
     * @return 统一返回R类
     */
    @Transactional
    @Override
    public R writeExcel(HttpServletResponse response) {
        String templateFilePathAndName = filePathConfig.getWriteExcelFilePath() + "sheet13_output_template.xlsx";

        //从数据库中查询对应表格
        List<TechnologyCompetition> technologyCompetitionList = technologyCompetitionMapper.selectList(null);
        List<TechnologyCompetitionAward> technologyCompetitionAwardList = technologyCompetitionAwardMapper.selectList(null);

        //创建 templates 存放转换后的数据
        List<TechnologyCompetitionTemplate> list = new ArrayList<>();


        //将数据库对应的bean复制给导出表格bean
        //对查询出来的数据进行判断
        for (int i = 0; i < technologyCompetitionList.size(); i++) {
            TechnologyCompetitionTemplate template = new TechnologyCompetitionTemplate();
            String category = technologyCompetitionList.get(i).getCategory();

            if ("1".equals(category)) {
                template.setNationalCategory("√");
            } else if ("2".equals(category)) {
                template.setProvincialCategory("√");
            } else if ("3".equals(category)) {
                template.setSchoolCategory("√");
            }

            //将查询的结果的集合映射给模板对象
            BeanUtils.copyProperties(technologyCompetitionList.get(i), template);
            BeanUtils.copyProperties(technologyCompetitionAwardList.get(i), template);
            //设置导出模板的第一列序号
            template.setNum(i + 1);
            list.add(template);
        }

        //导出(匿名内部类SheetWriteHandler)
        //设置输出文件名
        response.setHeader("Content-disposition", "attachment;filename=" + outputFileName);

        //将封装好的模板对象放入网络流中返回给用户
        try {
            EasyExcel.write(response.getOutputStream()).withTemplate(templateFilePathAndName).registerWriteHandler(new SheetWriteHandler() {

                @Override
                public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

                }

                @Override
                public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
                    //日志
                }


            }).sheet().doFill(list);
        } catch (IOException e) {
            e.printStackTrace();
        }


        return R.OK();
    }


    /**
     * 分页查询
     *
     * @param currentPage 当前页码
     * @param limit       每页需要呈现多少数据
     * @return
     */
    @Override
    public R selectPage(int currentPage, int limit) {
        log.info("执行到了TechnologyCompetitionServiceImpl的分页查询方法");
        Page<TechnologyCompetition> page1 = new Page<>(currentPage, limit);
        Page<TechnologyCompetitionAward> page2 = new Page<>(currentPage, limit);
        //使用QueryWrapper设置查询条件
        QueryWrapper<TechnologyCompetition> wrapper1 = new QueryWrapper<>();
        QueryWrapper<TechnologyCompetitionAward> wrapper2 = new QueryWrapper<>();
        //查询时排除掉数据库中gmtCreate、gmtModified、deleted字段

        wrapper1.eq("deleted", 0);


        //设置查询条件 查询没有被逻辑删除的数据
        wrapper2.eq("deleted", 0);


        ArrayList<TechnologyCompetitionTemplate> list = new ArrayList<>();

        List<TechnologyCompetition> technologyCompetitionList = technologyCompetitionMapper.selectPage(page1, wrapper1).getRecords();
        List<TechnologyCompetitionAward> technologyCompetitionAwardList = technologyCompetitionAwardMapper.selectPage(page2, wrapper2).getRecords();
        for (int i = 0; i < technologyCompetitionList.size(); i++) {
            TechnologyCompetitionTemplate template = new TechnologyCompetitionTemplate();
            String category = technologyCompetitionList.get(i).getCategory();


            //将查询的结果的集合映射给模板对象
            BeanUtils.copyProperties(technologyCompetitionList.get(i), template);
            BeanUtils.copyProperties(technologyCompetitionAwardList.get(i), template);
            //设置导出模板的第一列序号
            template.setNum(i + 1);
            list.add(template);
        }
        //返回总记录数
        Integer total = technologyCompetitionMapper.selectCount(wrapper1);
        //返回总页数
        Integer pages = (total / limit) + 1;
        //返回R
        return R.OK().message("分页查询成功").data("list", list).data("total", total).data("pages", pages);
    }

    /**
     * 从网页获取数据验证id是否为空 如果为空则插入到数据库
     *
     * @param template 传入的对象
     * @return 返回影响的行数
     */

    @Override
    @Transactional
    public R insertOrUpdate(TechnologyCompetitionTemplate template) {
        //创建数据库对应实体类
        TechnologyCompetition technologyCompetition = new TechnologyCompetition();
        TechnologyCompetitionAward technologyCompetitionAward = new TechnologyCompetitionAward();
        log.info("R.getR().getMessage():" + R.getR().getMessage());


        // 将模版中的数据映射进数据库实体类
        BeanUtils.copyProperties(template, technologyCompetition);
        BeanUtils.copyProperties(template, technologyCompetitionAward);

        String category = template.getCategory();
        if ("国家级".equals(category)) {
            technologyCompetition.setCategory("1");
        } else if ("省部级".equals(category)) {
            technologyCompetition.setCategory("2");
        } else if ("校级".equals(category)) {
            technologyCompetition.setCategory("3");
        }

        String id = template.getId();
        //如果id为空则执行插入操作 不为空则执行修改操作
        if (id == null) {
            //返回受影响行数
            int insert = technologyCompetitionMapper.insert(technologyCompetition);
            // 从technologyCompetition中获取雪花算法生成的id并设置进technologyCompetitionAward 保证两者主键id一致
            technologyCompetitionAward.setId(technologyCompetition.getId());
            technologyCompetitionAwardMapper.insert(technologyCompetitionAward);
            log.info("insert:" + insert);
            if (insert == 1) {
                return R.OK().code(ResultCode.SUCCESS).message("插入成功！");
            } else {
                return R.ERROR().code(ResultCode.INSERTERROR).message("插入失败,id重复！");
            }
        } else {
            QueryWrapper<TechnologyCompetition> wrapper1 = new QueryWrapper<>();
            wrapper1.eq("id", id)
                    .eq("deleted", 0);

            QueryWrapper<TechnologyCompetitionAward> wrapper2 = new QueryWrapper<>();
            wrapper2.eq("id", id)
                    .eq("deleted", 0);
            //返回受影响行数
            int update = technologyCompetitionMapper.update(technologyCompetition, wrapper1);
            technologyCompetitionMapper.update(technologyCompetition, wrapper1);
            technologyCompetitionAwardMapper.update(technologyCompetitionAward, wrapper2);
            log.info("update:" + update);
            if (update == 1) {
                return R.OK().code(ResultCode.SUCCESS).message("更新成功！");
            } else {
                return R.ERROR().code(ResultCode.UPDATEERROR).message("更新失败！,找不到该id的记录");

            }
        }

    }

    /**
     * 根据id删除记录
     *
     * @param template 传入封装好的pojo
     * @return 返回影响的行数
     */
    @Override
    @Transactional

    public R deleteById(TechnologyCompetition template) {
        TechnologyCompetition technologyCompetition = new TechnologyCompetition();
        TechnologyCompetitionAward technologyCompetitionAward = new TechnologyCompetitionAward();

        QueryWrapper<TechnologyCompetition> wrapper1 = new QueryWrapper<>();
        QueryWrapper<TechnologyCompetitionAward> wrapper2 = new QueryWrapper<>();
        wrapper1.eq("id", template.getId())
                .eq("deleted", 0);
        wrapper2.eq("id", template.getId())
                .eq("deleted", 0);
        BeanUtils.copyProperties(template, technologyCompetition);
        BeanUtils.copyProperties(template, technologyCompetitionAward);
        //将传入的实体类的deleted属性置为逻辑删除（1）
        technologyCompetition.setDeleted(1);
        technologyCompetitionAward.setDeleted(1);
        int delete = technologyCompetitionMapper.update(technologyCompetition, wrapper1);
        technologyCompetitionAwardMapper.update(technologyCompetitionAward, wrapper2);
        if (delete == 1) {
            return R.OK().code(ResultCode.SUCCESS).message("删除成功！");
        } else {
            return R.ERROR().code(ResultCode.DELETEERROR).message("删除失败,找不到该id的记录！");

        }
    }

    /**
     * 模糊查询
     *
     * @param currentPage 当前页码
     * @param limit       每页需要呈现的数据条数
     * @param entity      包含模糊查询参数的实体类
     * @return 返回通过结果类
     */

    @Override
    public R selectByCondition(int currentPage, int limit, TechnologyCompetition entity) {

        Page<TechnologyCompetition> entityPage = new Page<>(currentPage, limit);
        QueryWrapper<TechnologyCompetition> wrapper = new QueryWrapper<>();
        // 因为需求是单条件查询，所以获取所有可能包含有查询条件的属性，判断是否为空作为是否为查询条件的依据
        // 教材名称
        String projectName = entity.getProjectName();
        log.info("projectName:============" + projectName);
        // 教材建设类别
        String category = entity.getCategory();
        wrapper.eq("deleted", 0);
        if (projectName != null) {
            wrapper.like("project_name", projectName);
        } else if (category != null) {
            wrapper.like("category", category);
        }


        List<TechnologyCompetition> records = technologyCompetitionMapper.selectPage(entityPage, wrapper).getRecords();

        //创建 templates 存放转换后的数据
        List<TechnologyCompetitionTemplate> list = new ArrayList<>();

        //对查询出来的数据进行判断
        for (int i = 0; i < records.size(); i++) {
            TechnologyCompetition technologyCompetition = records.get(i);
            TechnologyCompetitionTemplate template = new TechnologyCompetitionTemplate();
            String id = technologyCompetition.getId();
            TechnologyCompetitionAward technologyCompetitionAward = technologyCompetitionAwardMapper.selectById(id);
            //将查询的结果的集合映射给模板对象
            BeanUtils.copyProperties(technologyCompetition, template);
            BeanUtils.copyProperties(technologyCompetitionAward, template);
            //设置导出模板的第一列序号
            template.setNum(i + 1);
            log.info("template2:============" + template);

            list.add(template);
        }


        if (records.isEmpty()) {
            return R.ERROR().code(ResultCode.SELECTNULL).message("条件查询结果为空");
        } else {
            //返回总记录数
            Integer total = technologyCompetitionMapper.selectCount(wrapper);
            log.info("total:" + total);
            //返回总页数
            Integer pages = (total / limit) + 1;
            return R.OK().message("分页查询成功").data("list", list).data("total", total).data("pages", pages);
        }
    }

    /**
     * 模糊查询并导出文件
     *
     * @param entity   使用entity接受模糊查询的条件参数
     * @param response response
     * @return 统一返回R类
     */
    @Override
    public R writeByCondition(TechnologyCompetition entity, HttpServletResponse response) {
        QueryWrapper<TechnologyCompetition> wrapper = new QueryWrapper<>();
        // 因为需求是单条件查询，所以获取所有可能包含有查询条件的属性，判断是否为空作为是否为查询条件的依据
        // 教材名称
        String projectName = entity.getProjectName();
        // 教材建设类别
        String category = entity.getCategory();

        wrapper.eq("deleted", 0);
        if (projectName != null) {
            wrapper.like("project_name", projectName);
        }
        if (category != null) {
            wrapper.like("category", category);

        }

        List<TechnologyCompetition> records = technologyCompetitionMapper.selectList(wrapper);

        log.info("records.size()" + records.size());
        //创建 templates 存放转换后的数据
        List<TechnologyCompetitionTemplate> list = new ArrayList<>();

        //对查询出来的数据进行判断
        for (int i = 0; i < records.size(); i++) {
            TechnologyCompetitionTemplate template = new TechnologyCompetitionTemplate();
            TechnologyCompetition technologyCompetition = records.get(i);
            category = technologyCompetition.getCategory();
            String id = technologyCompetition.getId();
            if ("1".equals(category)) {
                template.setNationalCategory("√");
            } else if ("2".equals(category)) {
                template.setProvincialCategory("√");
            } else if ("3".equals(category)) {
                template.setSchoolCategory("√");
            }

            TechnologyCompetitionAward technologyCompetitionAward = technologyCompetitionAwardMapper.selectById(id);
            //将查询的结果的集合映射给模板对象
            BeanUtils.copyProperties(technologyCompetition, template);
            BeanUtils.copyProperties(technologyCompetitionAward, template);
            //设置导出模板的第一列序号
            template.setNum(i + 1);

            list.add(template);
        }
        //设置输出文件名
        String templateFilePathAndName = filePathConfig.getWriteExcelFilePath() + "sheet13_output_template.xlsx";

        if (list.isEmpty()) {
            return R.ERROR().code(ResultCode.SELECTNULL).message("条件查询结果为空");
        } else {
            //将封装好的模板对象放入网络流中返回给用户
            try {
                //导出(匿名内部类SheetWriteHandler)
                response.setHeader("Content-disposition", "attachment;filename=" + outputFileName);

                EasyExcel.write(response.getOutputStream()).withTemplate(templateFilePathAndName).registerWriteHandler(new SheetWriteHandler() {

                    @Override
                    public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {

                    }

                    @Override
                    public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
                        //日志
                    }


                }).sheet().doFill(list);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return R.OK().message("模糊查询并下载成功");
        }

    }


}
